﻿using Autofac;
using Autofac.Builder;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using ZFY.Core;
using ZFY.UnitOfWork;

namespace ZFY.AspNetCore
{
    public class ZFYAutofacModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder containerBuilder)
        {


            var assemblies = AllAssemblies;
            //var assembly = Assembly.GetExecutingAssembly();
            //Assembly[] assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(Assembly.Load).ToArray() ;

            

             var interceptors = assemblies.SelectMany(x => x.GetTypes().Where(v => typeof(IInterceptor).IsAssignableFrom(v) || typeof(IAsyncInterceptor).IsAssignableFrom(v)));

            containerBuilder.RegisterTypes(interceptors.ToArray());

            


            foreach (var assembly in assemblies)
            {
                
                foreach (var type in assembly.GetTypes().Where(x=>typeof(IDependency).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract && !x.IsSealed))
                {


                    if (type.IsGenericType && type.GetInterfaces().Any(x => x.IsGenericType))
                    {
                        var generic =  containerBuilder.RegisterGeneric(type);

                        AutofacMouldEx.RegisterImplementation(generic, type).Setting(type);
                        
                    }
                    else
                    {
                        var normal = containerBuilder.RegisterType(type);

                        AutofacMouldEx.RegisterImplementation(normal, type).Setting(type);

                    }

                }


                //foreach (var item in assembly.GetTypes().Where(x => typeof(ITransientDependency).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract))
                //{
                //    if (item.IsGenericType && item.GetInterfaces().Any(x => x.IsGenericType))
                //    {
                //       var res2= containerBuilder.RegisterGeneric(item).As(item.GetInterfaces().FirstOrDefault(x => x.IsGenericType)).InstancePerDependency();

                //        OtherSetting(item, res2);

                //        continue;

                //    }

                //    var res1 = containerBuilder.RegisterType(item).IfNotRegistered(item).AsImplementedInterfaces().InstancePerDependency();
                    
                //    OtherSetting(item, res1);

                //}

                //foreach (var item in assembly.GetTypes().Where(x => typeof(IScopeDependency).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract))
                //{
                //    if (item.IsGenericType && item.GetInterfaces().Any(x => x.IsGenericType))
                //    {
                //        var res1 = containerBuilder.RegisterGeneric(item).As(item.GetInterfaces().FirstOrDefault(x => x.IsGenericType)).InstancePerLifetimeScope();

                //        OtherSetting(item, res1);

                //        continue;
                //    }

                //    var res2 = containerBuilder.RegisterType(item).AsImplementedInterfaces().InstancePerLifetimeScope();

                //    OtherSetting(item, res2);

                //}
                //foreach (var item in assembly.GetTypes().Where(x => typeof(ISignleDependency).IsAssignableFrom(x) && x.IsClass && !x.IsAbstract))
                //{
                //    if (item.IsGenericType && item.GetInterfaces().Any(x => x.IsGenericType))
                //    {
                //      var res2=  containerBuilder.RegisterGeneric(item).As(item.GetInterfaces().FirstOrDefault(x => x.IsGenericType)).SingleInstance();

                //        OtherSetting(item, res2);

                //        continue;
                       

                //    }
                //   var res1 = containerBuilder.RegisterType(item).AsImplementedInterfaces().SingleInstance();

                //    OtherSetting(item, res1);
                //}

            }

        }

        //private static void OtherSetting(Type item, IRegistrationBuilder<object, ReflectionActivatorData, DynamicRegistrationStyle> res1)
        //{

        //    if (typeof(IHasPropertiesAutowired).IsAssignableFrom(item))
        //    {
        //        res1.PropertiesAutowired();
        //    }

        //    if (UnitOfWorkHelper.IsUnitOfWorkType(item.GetTypeInfo()))
        //    {
        //        res1.EnableInterfaceInterceptors()
        //        .InterceptedBy(typeof(UnitOfWorkInterceptor));
        //    }


        //}

        //private static void OtherSetting(Type item, IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> res2)
        //{
        //    if (UnitOfWorkHelper.IsUnitOfWorkType(item.GetTypeInfo()))
        //    {
        //        res2.EnableInterfaceInterceptors()
        //        .InterceptedBy(typeof(UnitOfWorkInterceptor));
        //    }

        //    if (typeof(IHasPropertiesAutowired).IsAssignableFrom(item))
        //    {
        //        res2.PropertiesAutowired();
        //    }
        //}


        public static List<Assembly> AllAssemblies
        {
            get
            {
                var list = new List<Assembly>();
                var deps = DependencyContext.Default;
                var libs = deps.CompileLibraries.Where(lib => lib.Type == "project" || lib.Name.StartsWith("ZFY") );
                foreach (var lib in libs)
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    list.Add(assembly);
                    
                }
                return list;
            }
        }
    }

    public static class AutofacMouldEx
    {
        public static void Setting<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> T, Type type)
        {

            if (type.FullName == typeof(ZFYServiceProvider).FullName)
            {

            }

            if (typeof(ITransientDependency).IsAssignableFrom(type))
            {
                T = T.InstancePerDependency();
            }
            else if (typeof(IScopeDependency).IsAssignableFrom(type))
            {
                T = T.InstancePerLifetimeScope();
            }
            else if (typeof(ISignleDependency).IsAssignableFrom(type))
            {
                T = T.SingleInstance();
            }

            if (UnitOfWorkHelper.IsUnitOfWorkType(type.GetTypeInfo()))
            {
                T = T.EnableInterfaceInterceptors()
                .InterceptedBy(typeof(UnitOfWorkInterceptor));
            }

            if (typeof(IHasPropertiesAutowired).IsAssignableFrom(type))
            {
                T = T.PropertiesAutowired();
            }
        }
        public static IRegistrationBuilder<TLimit, ReflectionActivatorData, DynamicRegistrationStyle> RegisterImplementation<TLimit>(IRegistrationBuilder<TLimit, ReflectionActivatorData, DynamicRegistrationStyle>  T, Type type)
        {
            if (typeof(ISelfDependency).IsAssignableFrom(type))
            {
                return T.AsSelf();
            }
            else
            {
                return T.As(type.GetInterfaces().FirstOrDefault(x => x.IsGenericType));
            }
        }

        public static IRegistrationBuilder<TLimit, TConcreteActivatorData, SingleRegistrationStyle> RegisterImplementation<TLimit, TConcreteActivatorData>(IRegistrationBuilder<TLimit, TConcreteActivatorData, SingleRegistrationStyle> T, Type type) where TConcreteActivatorData : IConcreteActivatorData
        {
            if (typeof(ISelfDependency).IsAssignableFrom(type))
            {
                return T.AsSelf();
            }
            else
            {
                return T.AsImplementedInterfaces();
            }
        }
    }
}
